package org.hw.base;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;

public class ClassDemo {
	public static void main(String[] args)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {
		/*
		 * // 第一种 Girl girl=new Girl("女孩", 10); Class<?>
		 * girlClass=girl.getClass();
		 * 
		 * System.out.println(girl.getAge());
		 * System.out.println(girlClass.getName());
		 * System.out.println(girlClass.getSuperclass().getName());
		 */

		
////		第二种 
//		Class<Girl> girlClass = Girl.class;
//		Girl girl = null;
//		girl = girlClass.newInstance();
//		try {
//			Constructor<?> constructor = girlClass.getConstructor(new Class[] {});
//			girl = (Girl) constructor.newInstance(new Object[] {});
//			// girl=(Girl)girlClass.getConstructor(newClass[]{String.class,Integer.class}).newInstance(newObject[]{"何伟",23});
//		} catch (IllegalArgumentException e) {
//			e.printStackTrace();
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (NoSuchMethodException e) {
//			e.printStackTrace();
//		} catch (SecurityException e) {
//			e.printStackTrace();
//		}
//		System.out.println(girl);
//		System.out.println(girlClass.getName());
//		System.out.println(girlClass.getSuperclass().getName());
//		 

//		第三种
		// Class<Girl> girlClass=(Class<Girl>) Class.forName("Girl");
		Class<?> girlClass = Class.forName("org.hw.base.Girl");
		System.out.println(girlClass.getName());
		System.out.println(girlClass.getSuperclass().getName());
		Girl girl = null;
		// 调用默认的无参构造方法
		// girl=(Girl)girlClass.newInstance();
		try {
			// 通过class对象调用带参构造方法
			Constructor<?> constructor = girlClass.getConstructor(new Class[] { String.class, Integer.class });
			girl = (Girl) constructor.newInstance(new Object[] { "何伟", 23 });
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		System.out.println(girl);
		
		Method method = null;
		String methStr=null;
		try {
//			getMethod获取公有的方法
			// 获取类的public修饰的toString方法，参数为空,所以参数对应的类型数组是new Class[] {}
//			method = girlClass.getMethod("toString", new Class[] {});
//			getDeclaredMethod获取任何一个方法，包括私有的
			// 获取类的private修饰的show方法，参数为String类型，所以参数对应的类型数组是new Class[]{String.class}
			method=girlClass.getDeclaredMethod("show", new Class[]{String.class});
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		} catch (SecurityException e1) {
			e1.printStackTrace();
		}
		System.out.println(method);
		System.out.println(method.getName());
		try {
			//调用girl对象的公有的toString方法,如果调用静态方法对象参数可以传null
//			methStr=(String) method.invoke(girl, new Object[]{});
			//调用girl对象的私有的show方法之前先设置setAccessible为true
			method.setAccessible(true);
			methStr=(String) method.invoke(girl, new Object[]{"何伟"});
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		System.out.println(methStr);
		
		Method[] methods=girlClass.getDeclaredMethods();
		for (Method mt : methods) {
			System.out.println(mt.getName()+"---"+mt.getModifiers()+"---"+mt.getReturnType());
//			System.out.println(mt);
		}
		
		try {
			Field field=girlClass.getDeclaredField("name");
			field.setAccessible(true);
			System.out.println(field.get(girl));
			field.set(girl, "蓝天迷梦");
			System.out.println(field.get(girl));
			
//			Field field=girlClass.getField("PI");
//			System.out.println(field.getName());
//			System.out.println(field.getInt(girl));
//			field.setInt(girl, 10);
//			System.out.println(field.getInt(girl));
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
		/*
		 * 第四种
		 * //基本类型获取Class对象，基本类型（int）没有父类,基本类型的包装类（Integer）有父类 // Class<?>
		 * intClass=int.class; // Class<?> intClass=Integer.TYPE; Class<?>
		 * intClass=Integer.class; System.out.println(intClass.getName());
		 * System.out.println(intClass.getSuperclass().getName());
		 */
		
//		Class<?> strClass=String.class;
		Class<?> strClass=Class.forName("java.lang.String");
		Object array=Array.newInstance(strClass, 5);
		Array.set(array, 2, "二");
		System.out.println(Array.get(array, 2));


		/*----------------------------------- 获取方法参数的注解 -----------------------------------*/
		/**
		 * 获取注解单独拧了出来, 因为它并不是专属于 Class 对象的一种信息, 每个变量, 方法和构造器都可以
		 * 被注解修饰, 所以在反射中, Field, Constructor 和 Method 类对象都可以调用下面这些方法获取标
		 * 注在它们之上的注解。
		 * Annotation[] getAnnotations(): 获取该对象上的所有注解
		 * Annotation getAnnotation(Class annotaionClass): 传入注解类型 , 获取该对象上的特定一个注解
		 * Annotation[] getDeclaredAnnotations(): 获取该对象上的显式标注的所有注解, 无法获取 继承下来的注解
		 * Annotation getDeclaredAnnotation(Class annotationClass): 根据 , 获取该对象上的特定一个注解, 无法获取 继承下来的注解
		 * 只有注解的 @Retension 标注为 RUNTIME 时, 才能够通过反射获取到该注解
		 * */

		// 获取MyClass的Class对象
		Class<?> clazz = MyClass.class;

		// 获取myMethod方法
		Method myMethod = clazz.getDeclaredMethod("myMethod", String.class);

		// 获取方法的参数
		Parameter[] parameters = myMethod.getParameters();
		// 获取方法的注解
//		Annotation myAnnotation=myMethod.getAnnotation(MyAnnotation.class);

		// 遍历参数
		for (Parameter parameter : parameters) {
			// 检查参数上是否存在@MyAnnotation注解
			if (parameter.isAnnotationPresent(MyAnnotation.class)) {
				MyAnnotation myAnnotation = parameter.getAnnotation(MyAnnotation.class);
				// 输出注解的值
				System.out.println("Annotation value: " + myAnnotation.value());
			}
		}

	}
}

// 定义一个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface MyAnnotation {
	String value() default "defaultValue";
}

// 定义一个类，其中包含使用了@MyAnnotation注解的方法
class MyClass {
	public void myMethod(@MyAnnotation(value = "Hello") String param) {
		// 方法体
	}
}